<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Loop (解析字符串)</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link href="../css/default.css" rel="stylesheet" type="text/css">
</head>
<body>

<h1>Loop (解析字符串)</h1>

<p>从一个字符串中获取子字符串 (片段), 每次一个.</p>

<pre class="Syntax">Loop, Parse, InputVar [, Delimiters, OmitChars] </pre>
<h3>参数</h3>
<table class="info">
  <tr>
    <td width="15%">Parse</td>
    <td width="85%">此参数必须为单词 PARSE, 且与其他循环类型不同, 它不能为包含单词 PARSE 的变量引用.</td>
  </tr>
  <tr>
    <td>InputVar</td>
    <td><p>需要被解析的变量名称. 不要把名称括在百分号中, 除非您希望使用变量的 <em>内容</em> 作为被解析的变量名.</p>    </td>
  </tr>
  <tr>
    <td>Delimiters</td>
    <td><p>如果此参数为空或省略, 那么将把 <em>InputVar</em> 中的每个字符解析为单独的子字符串.</p>
      <p>如果此参数为 <strong>CSV</strong>, 那么将把 <em>InputVar</em> 按逗号分隔值格式标准进行解析. 这是一个由 MS Excel 生成的 CSV 格式行的示例: "first field",SecondField,"the word ""special"" is quoted literally",,"last field, has literal comma"</p>
      <p>其他情况下, <em>Delimiters</em> 中可以包含一个或多个字符 (区分大小写), 其中的每个都被用来确定 <em>InputVar</em> 中子字符串之间的边界.</p>
      <p>分隔符不会被视为子字符串自身的一部分. 此外, 在 <em>InputVar</em> 中如果一对分隔符之间没有任何字符, 那么相应的子字符串将为空.</p>
      <p>例如: `, (转义的逗号) 将根据逗号每次出现的位置分割字符串. 同样地, 使用 %A_Tab%%A_Space% 作为分隔符将在 <em>InputVar</em> 中每次遇到空格或 tab 时开始一个新的子字符串.</p>
      <p>要使用字符串而不是字符作为分隔符, 首先使用 <a href="StringReplace.htm">StringReplace</a> 把这个字符串在所有出现的地方替换为文本中从未使用的单个字符, 例如这些特殊字符的其中一个: ¢¤¥¦§©ª«®µ¶. 参考这个例子, 其中使用字符串 &lt;br&gt; 作为分隔符:</p>
      <pre>StringReplace, NewHTML, HTMLString, &lt;br&gt;, ¢, All
Loop, parse, NewHTML, ¢ <em>; 使用 ¢ 解析字符串.</em>
{
...
}</pre></td>
  </tr>
  <tr>
    <td>OmitChars</td>
    <td><p>可选的字符列表 (区分大小写), 用于从每个子字符串的开始和结尾部分移除这些字符. 例如, 如果使用 <em>OmitChars</em> is %A_Space%%A_Tab%, 每个解析出来的子字符串中开始和结尾部分 (但中间的不会) 的空格和 tab 将被移除.</p>
    <p>如果 <em>Delimiters</em> 为空, 那么 <em>OmitChars</em> 表示应该考虑移除哪些字符 (它们将不会出现在循环中).</p>
    <p>与其他大多数命令的最后一个参数不同, 在 <em>OmitChars</em> 中的逗号必须进行转义 (`,).</p></td>
  </tr>
</table>

<h3>备注</h3>
<p>当您想对包含在字符串中的片段逐个进行操作时, 字符串解析循环很有用. 解析循环比 <a href="StringSplit.htm">StringSplit</a> 使用更少的内存 (因为 StringSplit 创建了持久的数组) 且在大多数情况下更容易使用.</p>
<p><a name="LoopField"></a>内置变量 <strong>A_LoopField</strong> 存在于任何解析循环中. 它包含了 <em>InputVar</em> 中当前子字符串 (片段) 的内容. 如果一个内层解析循环包含在一个外层解析循环中, 则最内层循环的片段将具有优先权.</p>
<p>尽管不存在内置变量 "A_LoopDelimiter", 不过在此页面最底部的例子演示了如何检测在分割每个片段时是由于遇到哪个分隔符.</p>
<p><em>InputVar</em> 或其片段没有大小限制. 此外, 如果 <em>InputVar</em> 的内容在循环执行期间改变了, 循环将 "无视" 这些变化, 因为它正在操作的是原始内容的临时副本.</p>
<p>要在解析前按不同的顺序排列字段, 使用 <a href="Sort.htm">Sort</a> 命令.</p>
<p>参见 <a href="Loop.htm">Loop</a> 了解关于 <a href="Block.htm">区块</a>, <a href="Break.htm">Break</a>, <a href="Continue.htm">Continue</a>, 和 A_Index 变量 (其存在于各种类型的循环中) 的相关信息.</p>
<h3>相关</h3>
<p><a href="StringSplit.htm">StringSplit</a>, <a href="LoopReadFile.htm">文件读取循环</a>, <a href="Loop.htm">Loop</a>, <a href="Break.htm">Break</a>, <a href="Continue.htm">Continue</a>, <a href="Block.htm">区块</a>, <a href="Sort.htm">Sort</a>, <a href="FileSetAttrib.htm">FileSetAttrib</a>, <a href="FileSetTime.htm">FileSetTime</a></p>
<h3>示例</h3>
<pre class="NoIndent"><em>; 示例 #1:</em>
Colors = red,green,blue
Loop, parse, Colors, `,
{
    MsgBox, Color number %A_Index% is %A_LoopField%.
}</pre>
<p>&nbsp;</p>
<pre class="NoIndent"><em>; 示例 #2: 按行读取变量的内容, 一行接一行 (类似于 <a href="LoopReadFile.htm">文件读取</a> 循环).
; 通过 <a href="FileRead.htm">FileRead</a> 可以把文件加载到变量中:</em>
Loop, parse, FileContents, `n, `r  <em>; 在 `r 之前指定 `n, 这样可以同时支持对 Windows 和 Unix 文件的解析.</em>
{
    MsgBox, 4, , Line number %A_Index% is %A_LoopField%.`n`nContinue?
    IfMsgBox, No, break
}</pre>
<p>&nbsp;</p>
<pre class="NoIndent"><em>; 示例 #3: 除了用于剪贴板外, 这个例子和上一个一样.
; 每当剪贴板包含文件时这个例子很有用, 例如从打开的资源管理器窗口
; 复制的那些 (程序自动把这些文件转换为它们的文件名):</em>
Loop, parse, clipboard, `n, `r
{
    MsgBox, 4, , File number %A_Index% is %A_LoopField%.`n`nContinue?
    IfMsgBox, No, break
}</pre>
<p>&nbsp;</p>
<pre class="NoIndent"><em>; 示例 #4: 解析逗号分隔值 (CSV) 文件:</em>
Loop, read, C:\Database Export.csv
{
    LineNumber = %A_Index%
    Loop, parse, A_LoopReadLine, CSV
    {
        MsgBox, 4, , Field %LineNumber%-%A_Index% is:`n%A_LoopField%`n`nContinue?
        IfMsgBox, No
            return
    }
}</pre>
<p>&nbsp;</p>
<pre class="NoIndent"><em>; 下面的例子类似于解析循环, 不过它还提供了识别
; 遇到了哪个分隔符.</em>

<em>; 初始化待搜索字符串.</em>
Colors = red,green|blue;yellow|cyan,magenta
<em>; 初始化开始搜索时基于零的偏移.</em>
field_begin := 0
<em>; 初始化分隔符.</em>
delimiters = ,|;
Loop
{
    <em>; 找到下一个分隔符的基于零的索引, 相对于当前片段的起始处.</em>
    field_length := DllCall("shlwapi\StrCSpn", "uint", &amp;Colors + field_begin, "uint", &amp;delimiters, "uint")
    <em>; 从输入字符串中提取片段.</em>
    field := SubStr(Colors, field_begin + 1, field_length)
    <em>; 从输入字符串中提取分隔符.</em>
    delimiter := SubStr(Colors, field_begin + field_length + 1, 1)
    
    MsgBox % "field: " field "`ndelimiter: " delimiter
    
    <em>; 如果分隔符为空, 那么 StrCSpn 到达了输入字符串的末尾.</em>
    if delimiter =
        break
    <em>; 增加到下一个片段的开始处.</em>
    field_begin += field_length + 1
}</pre>

</body>
</html>
